/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Module handling properties of a single connection entry (Header)
 * \author Antti Maula <antti.maula@tkk.fi>
 */
#ifndef _CONNECTIONLISTENTRY_H_
#define _CONNECTIONLISTENTRY_H_
#include "buffer.h"
#include "connection.h"
#include "delayedlink.h"
#include "instrumentation.h"
#include "connectiontypes.h"
#include <inttypes.h>
#include <pthread.h>

/** Flags for a single connection.
 *
 */
typedef enum { 
  connectionEntryFlag_SocketActive             = (1<<0),    ///< Is this socket active (will be processed)
  connectionEntryFlag_AutoReconnect            = (1<<1),    ///< Auto reconnect will be attempted on this socket on failure.
  connectionEntryFlag_DelayedLink              = (1<<2),    ///< This link is delayd. More information in DelayedLinkCtrl structure pointer.
  connectionEntryFlag_DataInOutputBuffer       = (1<<3),    ///< This entry has data in outputbuffer, hence special processing required.
  connectionEntryFlag_LinkAuthenticated        = (1<<4),    ///< Is the link authenticated?
  connectionEntryFlag_LinkHub2Hub              = (1<<5),    ///< Link has been detected to be a Hub2Hub connection.
  connectionEntryFlag_LinkAPService            = (1<<6),    ///< Link has been detected to be an APService connection.
  connectionEntryFlag_LinkAPClient             = (1<<7),    ///< Link has been detected to be an APClient connection.
  connectionEntryFlag_SelectSetRead            = (1<<8),    ///< Should be added to read-fd-set.
  connectionEntryFlag_SelectSetWrite           = (1<<9),    ///< Should be added to write-fd-set.
  connectionEntryFlag_SelectSetException       = (1<<10),   ///< Should be added to exception-fd-set.
  connectionEntryFlag_RejectBroadcasts         = (1<<11),   ///< This link does not accept broadcasts (slow or expensive link)
  connectionEntryFlag_SkipOnce                 = (1<<12),   ///< Dispatches will skip this entry once and reset flag.
  connectionEntryFlag_PendingAsyncCommand      = (1<<13)    ///< This entry has a GIMnetAP layer command pending
} EConnectionEntryFlags;


/** Socket type (server or client)
 *
 */
typedef enum {
  KConnectionType_Unknown       = 0,
  KConnectionType_Server        = 1,
  KConnectionType_Client        = 2
} EConnectionType;


/** Connection state.
 *
 */
typedef enum {
  KConnectionState_Unknown      = 0,
  KConnectionState_Listening    = 1,
  KConnectionState_Connecting   = 2,
  KConnectionState_Connected    = 3,
  KConnectionState_Disconnected = 4
}EConnectionState;


/** Socket protocol in use.
 *
 */
typedef enum {
  KConnectionProtocol_Unknown   = 0,
  KConnectionProtocol_TCP       = 1,
  KConnectionProtocol_UDP       = 2,
  KConnectionProtocol_UNIX      = 3
}EConnectionProtocol;


/**
 * Type defines for HUB IDs
 *
 */
typedef uint16_t hubID_t;
typedef uint16_t clientID_t;
typedef uint32_t hubclientID_t;



/**
 * This is a structure grouping in data for controlling a delayed link
 */
typedef struct
{
  void *connectionList; ///< Pointer to connectionlist.
  TDelayedLinkInfo *delayedLinkInfo; ///< Delayed link information
  pthread_t linkMonitorThread;
  volatile int linkMonitorThreadRunning;
} TDelayedLinkCtrl;
 

/**
 * This is a structure for storing parameters controlling a
 * AutoReconnecting socket.
 */
typedef struct 
{
  unsigned int last_reconnect_timestamp;    ///< Timestamp of last reconnect attempt.
  unsigned int reconnect_min_interval;      ///< Minimum reconnect interval.
  unsigned int reconnect_attempt_count;     ///< Total number of reconnect attempts.
} TAutoReconnectCtrl;


/**
 * ID defines. (may be moved to somewhere else in near future)
 */
#define HUBID_ANY        0xFFFF    ///< Any HUB id, (aka. broadcast or other special)
#define CLIENTID_ANY     0xFFFF    ///< Any CLIENT id (aka. broadcast or other special)
#define HUBID_INVALID    0x0000    ///< Invalid ID for HUB.
#define CLIENTID_INVALID 0x0000    ///< Invalid ID for Client.


/**
 * Connection list Entry structure contains the information needed to
 * process one single connection.
 */
typedef struct
{
  hubclientID_t connectionID;   ///< Fully qualified node identifier
  EConnectionEntryFlags flags;  ///< Flags for this connection
  EConnectionProtocol protocol; ///< Protocol type; TCP/UDP/UNIX socket
  EConnectionType type;         ///< Link type; Server/Client.
  EConnectionState state;       ///< Link state; Listening/Connecting/Connected/Disconnected
  TBuffer inputBuffer;          ///< Incoming data buffer (per connection read buffer)
  TBuffer outputBuffer;         ///< Outgoing data buffer (per connection output buffer)
  TConnection *connection;      ///< 'Physical' connection pointer
  TInstrumentationEntryStats stats; ///< per-connection instrumentation information 
  int initialized;              ///< Flag; entry initialized
  uint64_t link_delay_us;       ///< Link delay in microseconds if known. Otherwise 0
  TDelayedLinkCtrl *delayedLinkCtrl; ///< Control info; Delayed link
  TAutoReconnectCtrl *autoReconnectCtrlPtr; ///< Control info: automatic reconnect
  union {
    TServerTCP *serverTCPptr;   ///< Pointer; TCP server implementation
    TClientTCP *clientTCPptr;   ///< Pointer; TCP client implementation
  };

} TConnectionListEntry;


/**
 * Creates and initializes a new connectionListEntry.
 *
 * @param ID               ID of this connection
 * @param flags            Connection flags for this entry
 * @param connection       Pointer to TConnection (This is OWNED here after this call!)
 *
 * @return                 Pointer to newly allocated TConnectionListEntry.
 * 
 */
TConnectionListEntry *connectionListEntryCreate( unsigned int ID,
                                                 EConnectionType type,
                                                 EConnectionState state,
                                                 EConnectionProtocol protocol,
						 EConnectionEntryFlags flags,
						 TConnection *connection );

/**
 * Initializes a pre-allocated entry.
 *
 * @param e                Pointer to init
 * @param ID               ID of this connection
 * @param type             Type of connection.
 * @param state            State of connection.
 * @param protocol         Protocol of connection.
 * @param flags            Connection flags for this entry
 * @param connection       Pointer to TConnection (This is OWNED here after this call!)
 *
 */
void connectionListEntryInit( TConnectionListEntry *e, 
			      unsigned int ID,
                              EConnectionType type,
                              EConnectionState state,
                              EConnectionProtocol protocol,
			      EConnectionEntryFlags flags,
			      TConnection *connection );

/**
 * De-initializes a entry, but does not free it's memory.
 *
 * @param e                Pointer to TConnectionListEntry to deinit
 * 
 */
void connectionListEntryDeinit( TConnectionListEntry *e );

void connectionListEntryCreateAutoReconnectCtrl( TConnectionListEntry *e, 
                                                 unsigned reconnect_min_interval_ms);
void connectionListEntryDestroyAutoReconnectCtrl( TConnectionListEntry *e );


/**
 * Destroys a entry. First calls Deinit, and after it frees the allocated resource. After calling this
 * the memory area pointed by 'e' is invalid.
 *
 * @param e                Pointer to TConnectionListEntry to destroy
 *
 */
void connectionListEntryDestroy( TConnectionListEntry *e );
void connectionListEntryDump( int l, const TConnectionListEntry *e );

#endif //_CONNECTIONLISTENTRY_H_
